package com.milling.web.utils;

import com.alibaba.fastjson2.JSONObject;
import com.mchange.lang.IntegerUtils;
import com.milling.business.BusinessConstants;
import com.milling.business.GlobalVariable;
import com.milling.business.domain.WmsCellInfo;
import com.milling.business.domain.WmsConfigInfo;
import com.milling.business.domain.WmsConfigSupply;
import com.milling.business.domain.WmsTaskInfo;
import com.milling.business.service.IWmsCellInfoService;
import com.milling.business.service.IWmsConfigInfoService;
import com.milling.business.service.IWmsConfigSupplyService;
import com.milling.business.service.IWmsTaskInfoService;
import com.milling.common.core.redis.RedisCache;
import com.milling.common.utils.SocketUtils;
import com.milling.common.utils.StringUtils;
import com.milling.common.utils.http.WmsApiUtils;
import com.milling.common.utils.modbus.ModbusServiceFactory;
import com.milling.common.utils.modbus.ModbusTcpService;
import com.milling.common.utils.scanner.SocketListener;
import com.milling.framework.websocket.AlertConfirmWebSocketHandler;
import com.milling.web.SpringContextHolder;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
import java.util.Date;
import java.util.List;
import java.util.Map;

//@Service
@Configuration
@ConditionalOnProperty(
        name = "mac.type",
        havingValue = "1",
        matchIfMissing = false // 当配置缺失时不加载
)
@Component
public class StorageScanner implements SocketListener.MessageCallback {
    private static final Logger logger = LoggerFactory.getLogger(StorageScanner.class);

    private volatile boolean reconnectFlag = true; // 控制重连的开关
    private final int MAX_RETRIES = 5; // 最大重试次数
    private final int RETRY_INTERVAL = 3000; // 重试间隔（毫秒）
    private final int MAX_SCAN_TIMES = 20; // 最大扫码次数，与其他扫码器保持一致
    private SocketListener currentListener; // 当前监听器引用
    private Thread listenerThread; // 监听线程
    private int scanAttempts = 0; // 扫码尝试次数

    @Value("${storage.ip}")
    private String storageIp;

    @Value("${storage.port}")
    private int storagePort;

    // 添加 Modbus 相关配置注入
    @Value("${modbus.tcp.host:192.168.237.88}") // 默认值防止未配置
    private String host;

    @Value("${modbus.tcp.port:502}")
    private int port;

    @Value("${modbus.tcp.poolSize:5}")
    private int poolSize;

    @Value("${modbus.tcp.slaveId:1}")
    private int slaveId;

    /*
        @Autowired
        private IWmsTaskInfoService wmsTaskInfoService;
    */
// 获取Modbus服务实例
//private final ModbusTcpService modbusTcpService = ModbusServiceFactory.getModbusService(host, port);
    private ModbusTcpService modbusTcpService;

    private SocketUtils socketUtils; // 声明为成员变量

    @Autowired
    private AlertConfirmWebSocketHandler webSocketHandler;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IWmsCellInfoService wmsCellInfoService;

    @Autowired
    private IWmsConfigInfoService wmsConfigInfoService;

    @Autowired
    private IWmsConfigSupplyService wmsConfigSupplyService;
    // 添加无参构造函数，确保 Spring 可以创建实例
    public StorageScanner() {
        // 初始化逻辑可以放在其他地方，例如 @PostConstruct 方法
    }

    // 添加初始化方法
    @PostConstruct
    public void init() {
        // 初始化 Modbus 服务
        modbusTcpService = ModbusServiceFactory.getModbusService(host, port, poolSize);
        logger.info("StorageScanner Modbus服务初始化完成 - {}:{}", host, port);

        // 初始化扫码器连接
        initConnection();
    }

    @Override
    public void onMessageReceived(String message) {
        logger.info("后库来料扫码结果： [" + message + "]");
        // 创建连接池
//        if("NoRead".equals(message)){
        if(message.contains("NoRead")){
            // 统一扫码重试逻辑，与其他扫码器保持一致
            if(scanAttempts <= MAX_SCAN_TIMES) {
                scanAttempts++;
                try {
                    //扫码 - 使用try-with-resources确保资源正确释放
                    try (SocketUtils tempSocketUtils = new SocketUtils(storageIp, storagePort)) {
                        tempSocketUtils.sendMessage("start");
                        Thread.sleep(50); // 统一延时时间
                    }
                } catch (Exception e) {
                    logger.error("StorageScanner sendMessage Fail, 尝试次数: {}", scanAttempts, e);
                    try{
                        modbusTcpService.writeHoldingRegister(slaveId, 550, 100);
                    } catch (Exception e1) {
                        logger.error("PLC写操作失败", e1);
                    }
                }
            } else {
                // 超过最大重试次数，重置计数器
                scanAttempts = 0;
                logger.error("后库扫码失败次数超过限制，已重置扫码计数器");
                // 可以在这里添加报警逻辑，发送WebSocket消息给前端
            }
        } else {
            // 扫码成功，重置扫码计数器
            scanAttempts = 0;
            logger.info("后库来料扫码结果： [" + message + "]");

            // 获取整个数组
            Map<String, String> map = redisCache.getCacheMap(GlobalVariable.ALREADY_STORAGE_CODES);

            if(StringUtils.isNotEmpty(map.get(message))){
                logger.info("已经处理过的后库来料二维码 " + message);
                return;
            }

            WmsCellInfo wmsCellInfo = new WmsCellInfo();
            wmsCellInfo.setCellStatus(BusinessConstants.CELL_STATUS_2);
            List<WmsCellInfo> wmsCellInfos = wmsCellInfoService.selectWmsCellInfoList(wmsCellInfo);
            if(wmsCellInfos.size() > 0){
                logger.info("有料正在入库中，稍后再入库");
                return;
            }

            int address600V = 0;
            try {
                address600V = modbusTcpService.readHoldingRegister( slaveId,600);//缓存库补料
            } catch (ModbusTransportException e) {
                e.printStackTrace();
                return;
            }
            if(address600V == 2){//缓存库补料

                WmsApiUtils wmsApiUtils = new WmsApiUtils();
                String boxcodeRespones = null;
                try {
                    boxcodeRespones = wmsApiUtils.queryDrillinfoByBoxid(message);
                    if (StringUtils.isEmpty(boxcodeRespones)) {
                        logger.error("缓存库补料API返回空响应 - 二维码: {}", message);
                        return;
                    }
                } catch (Exception e) {
                    logger.error("缓存库补料调用API失败 - 二维码: {}", message, e);
                    return;
                }
                String comeDrrilinfo = "";
//                WmsCellInfo wmsCellInfo = new WmsCellInfo();
                wmsCellInfo.setCellStatus(BusinessConstants.CELL_STATUS_1);
//                List<WmsCellInfo> wmsCellInfos = wmsCellInfoService.selectWmsCellInfoList(wmsCellInfo);
                wmsCellInfos = wmsCellInfoService.selectWmsCellInfoList(wmsCellInfo);
                if(wmsCellInfos.size() > 0){
                    wmsCellInfo = wmsCellInfos.get(0);
                    wmsCellInfo = parseBoxinfo(boxcodeRespones, wmsCellInfo);
                    wmsCellInfo.setBoxCode( message);
                    wmsCellInfo.setUpdateTime(new Date());
                    wmsCellInfo.setCellStatus(BusinessConstants.CELL_STATUS_2);
                    comeDrrilinfo = wmsCellInfo.getDrillInfo();
                    wmsCellInfoService.updateWmsCellInfo(wmsCellInfo);
                    try {
                        modbusTcpService.writeHoldingRegister(slaveId, 553, wmsCellInfo.getCellId().intValue());//缓存库位置
                        modbusTcpService.writeHoldingRegister(slaveId, 550, 0);
                        logger.info("预补料缓存库第 " + wmsCellInfo.getCellId() + " 位置"+wmsCellInfo.getsRow()+"行"+wmsCellInfo.getsColumn()+"列");
                    } catch (ModbusTransportException e) {
                        e.printStackTrace();
                    }
                }
                WmsConfigSupply wmsConfigSupply = new WmsConfigSupply();
                wmsConfigSupply.setDrillInfo(comeDrrilinfo);
                wmsConfigSupply.setConfigStatus(BusinessConstants.SUPPLY_STATUS_2);
                List<WmsConfigSupply> wmsConfigSupplyList = wmsConfigSupplyService.selectWmsConfigSupplyList(wmsConfigSupply);
                if(wmsConfigSupplyList.size() > 0) {
                    wmsConfigSupply = wmsConfigSupplyList.get(0);
                    WmsConfigInfo wmsConfigInfo = wmsConfigInfoService.selectWmsConfigInfoByConfigId(wmsConfigSupply.getConfigId());
                    wmsConfigInfoService.startConfigSupply(wmsConfigInfo);
                }
                return;
            }


            // 添加同步保护，防止并发修改冲突
            synchronized(this) {
                // 重新获取最新的map，防止并发修改丢失数据
                map = redisCache.getCacheMap(GlobalVariable.ALREADY_STORAGE_CODES);
                map.put(message, message);
                // 写回Redis
                redisCache.setCacheMap(GlobalVariable.ALREADY_STORAGE_CODES, map);
                logger.info("成功记录后库扫码: {}", message);
            }


/*
            if(StringUtils.isNotEmpty(GlobalVariable.ALREADY_STORAGE_CODES.get(message))){
                logger.info("已经处理过的后库来料二维码 " + message);
                return;
            }
            GlobalVariable.ALREADY_STORAGE_CODES.put(message, message);
*/

            try {
                // 获取Service实例
                IWmsCellInfoService wmsCellInfoService = SpringContextHolder.getBean(IWmsCellInfoService.class);

//                fangdai()
                WmsApiUtils wmsApiUtils = new WmsApiUtils();
                JSONObject jsonObject = new JSONObject();
//                jsonObject.put("box_id", message);
                String jsonString = jsonObject.toJSONString();
                String boxcodeRespones = wmsApiUtils.queryDrillinfoByBoxid(message);
//                WmsCellInfo wmsCellInfo = new WmsCellInfo();
                wmsCellInfo.setCellStatus(BusinessConstants.CELL_STATUS_1);

                List<WmsCellInfo> list2 = wmsCellInfoService.selectWmsCellInfoList(wmsCellInfo);
                if (list2.size() > 0) {
                    wmsCellInfo = list2.get(0);
                    wmsCellInfo = parseBoxinfo(boxcodeRespones, wmsCellInfo);
                    //XXXXXXX20250420
                    wmsCellInfo.setCellStatus(BusinessConstants.CELL_STATUS_2);
                    wmsCellInfoService.updateWmsCellInfo(wmsCellInfo);

                    WmsTaskInfo wmsTaskInfo = new WmsTaskInfo();
                    wmsTaskInfo.setTaskStatus(BusinessConstants.TASK_STATUS_2);
                    wmsTaskInfo.setTaskType(BusinessConstants.TASK_TYPE_4);//只有4才会触发扫码并进入此流程
                    IWmsTaskInfoService wmsTaskInfoService = SpringContextHolder.getBean(IWmsTaskInfoService.class);
                    List<WmsTaskInfo> wmsTaskInfoList = wmsTaskInfoService.selectWmsTaskInfoList(wmsTaskInfo);
                    logger.info("非前置补料  ");

                    if (wmsTaskInfoList.size() > 0) {
                        wmsTaskInfo = wmsTaskInfoList.get(0);
                        wmsTaskInfo.setBoxCode(wmsCellInfo.getBoxCode());
                        wmsTaskInfo.setBoxData(boxcodeRespones);
                        wmsTaskInfo.setDrillInfo(wmsCellInfo.getDrillInfo());
                        wmsTaskInfo.setDrillCount(wmsCellInfo.getDrillCount());
                        //XXXXXXX20250711
                        wmsTaskInfoService.updateWmsTaskInfo(wmsTaskInfo);
/*
                        WmsTaskInfo wmsTaskInfo2 = new WmsTaskInfo();
                        wmsTaskInfo2.setParentTaskId(wmsTaskInfo.getTaskId());
                        List<WmsTaskInfo> wmsTaskInfoList2 = wmsTaskInfoService.selectWmsTaskInfoList(wmsTaskInfo2);
                        if (wmsTaskInfoList2.size() > 0) {
                            wmsTaskInfo2 = wmsTaskInfoList2.get(0);
                            wmsTaskInfo2.setBoxCode(wmsCellInfo.getBoxCode());
                            wmsTaskInfo2.setBoxData(boxcodeRespones);
                            wmsTaskInfo2.setDrillInfo(wmsCellInfo.getDrillInfo());
                            wmsTaskInfo2.setDrillCount(wmsCellInfo.getDrillCount());
                        }
*/

                    } else {
                        logger.error("没有找到缓存库入料任务");
                    }
                    try {
                        //上料托盘数
                        modbusTcpService.writeHoldingRegister(slaveId, 553, wmsCellInfo.getCellId().intValue());
                        modbusTcpService.writeHoldingRegister(slaveId, 550, 0);
                        logger.info("补料缓存库第 " + wmsCellInfo.getCellId() + " 位置"+wmsCellInfo.getsRow()+"行"+wmsCellInfo.getsColumn()+"列");
                        Thread.sleep(50);
                    } catch (ModbusTransportException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                logger.info("[PLC]扫码成功，给550地址清0失败");
            }

            /*jsonObject.put("box_id", "920000024014");
            String jsonString = jsonObject.toJSONString();
            System.out.println("请求包：" + jsonString);
            String boxcodeRespones = HttpUtils.sendPostString("http://192.168.237.200:5001/RestAPI/QueryDrillinfoByBoxid", jsonString);
            System.out.println("返回包：" + boxcodeRespones);*/
            //扫码正常
        }

    }

/*    @Override
    public void onConnectionClosed() {
        System.out.println("[INFO] StorageScanner Connection closed by server");
    }*/

    // 初始化/重新连接的核心方法
    private synchronized void initConnection() {
        int retryCount = 0;
        while (reconnectFlag && retryCount < MAX_RETRIES) {
            try {
                closeExistingConnection(); // 清理旧连接

                Socket socket = new Socket(storageIp, storagePort);
                socket.setKeepAlive(true); // 启用Keep-Alive
                socket.setSoTimeout(30000); // 设置读超时

                currentListener = new SocketListener(socket, this);
                listenerThread = new Thread(currentListener);
                listenerThread.start();

                logger.info("成功连接到后库扫码器 {}:{}", storageIp, storagePort);
                return;
            } catch (ConnectException ce) {
                logger.error("连接失败 (尝试 {} / {}), 原因: {}",
                        retryCount+1, MAX_RETRIES, ce.getMessage());
                retryCount++;
                sleepForRetry();
            } catch (IOException e) {
                logger.error("连接异常", e);
                break;
            }
        }
        if (retryCount >= MAX_RETRIES) {
            logger.error("已达到最大重试次数，放弃连接");
        }
    }

    // 关闭现有连接
    private void closeExistingConnection() {
        try {
            if (currentListener != null) {
                currentListener.stopListening(); // 假设SocketListener有stop方法
            }
            if (listenerThread != null && listenerThread.isAlive()) {
                listenerThread.interrupt();
            }
        } catch (Exception e) {
            logger.warn("关闭旧连接时发生异常", e);
        }
    }

    // 休眠等待重试
    private void sleepForRetry() {
        try {
            Thread.sleep(RETRY_INTERVAL);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public void onConnectionClosed() {
        logger.warn("连接被关闭，尝试重新连接...");
        if (reconnectFlag) {
            initConnection(); // 触发重连
        }
    }

    // 添加手动停止方法
    public void stop() {
        reconnectFlag = false;
        closeExistingConnection();
    }

    // 添加连接状态检查方法
    public boolean isConnected() {
        return currentListener != null && listenerThread != null && listenerThread.isAlive();
    }

    // 添加诊断方法
    public String getConnectionStatus() {
        return String.format("StorageScanner连接状态: 监听器=%s, 线程=%s, 重连标志=%s",
                currentListener != null,
                (listenerThread != null && listenerThread.isAlive()),
                reconnectFlag);
    }

    @Override
    public void onError(String errorMsg) {
        System.err.println("[ERROR] " + errorMsg);
    }

    private WmsCellInfo parseBoxinfo(String boxInfo, WmsCellInfo wmsCellInfo) {
        try {
            if (StringUtils.isEmpty(boxInfo)) {
                logger.error("parseBoxinfo: boxInfo为空");
                return null;
            }

            JSONObject jsonObject = JSONObject.parseObject(boxInfo);
            if (jsonObject == null) {
                logger.error("parseBoxinfo: JSON解析失败 - {}", boxInfo);
                return null;
            }

            String Code = jsonObject.getString("Code");
            String Message = jsonObject.getString("Message");

            if(!"ok".equals(Message)) {
                logger.warn("parseBoxinfo: API返回非成功状态 - Code: {}, Message: {}", Code, Message);
                return null;
            }

            // 安全获取字段值，添加null检查
            String box_id = jsonObject.getString("box_id");
            String m_Drill_Count = jsonObject.getString("m_Drill_Count");
            String m_Drill_Info = jsonObject.getString("m_Drill_Info");
            String m_Drill_Size = jsonObject.getString("m_Drill_Size");
            String m_Drill_Edge = jsonObject.getString("m_Drill_Edge");
            String m_Drill_Type = jsonObject.getString("m_Drill_Type");
            String m_Drill_Grind_Count = jsonObject.getString("m_Drill_Grind_Count");

            wmsCellInfo.setBoxCode(box_id);
            wmsCellInfo.setDrillInfo(m_Drill_Info);

            // 安全的数值转换
            try {
                wmsCellInfo.setDrillCount(StringUtils.isNotEmpty(m_Drill_Count) ? Long.parseLong(m_Drill_Count) : 0L);
            } catch (NumberFormatException e) {
                logger.warn("parseBoxinfo: 钻头数量转换失败 - {}", m_Drill_Count);
                wmsCellInfo.setDrillCount(0L);
            }

            wmsCellInfo.setDrillEdge(m_Drill_Edge);
            wmsCellInfo.setDrillType(m_Drill_Type);

            // 安全的数值转换
            try {
                wmsCellInfo.setDrillGrindCount(StringUtils.isNotEmpty(m_Drill_Grind_Count) ? Long.parseLong(m_Drill_Grind_Count) : 0L);
            } catch (NumberFormatException e) {
                logger.warn("parseBoxinfo: 研磨次数转换失败 - {}", m_Drill_Grind_Count);
                wmsCellInfo.setDrillGrindCount(0L);
            }

            wmsCellInfo.setDrillSize(m_Drill_Size);
            return wmsCellInfo;

        } catch (Exception e) {
            logger.error("parseBoxinfo: 解析异常", e);
            return null;
        }
    }

    private void fangdai() {
        /*
                防呆保护
                WmsCellInfo wmsCellInfoQuery = new WmsCellInfo();
                wmsCellInfoQuery.setBoxCode(message);
                wmsCellInfoQuery.setCellStatus(BusinessConstants.CELL_STATUS_3);

                List<WmsCellInfo> list3 = wmsCellInfoService.selectWmsCellInfoList(wmsCellInfoQuery);
                if(null != list3 && list3.size() > 0){
                    logger.info("二维码针盒 [" + message + "] 已经在库中");

                    String alertMessage = "{\"type\":\"alert\",\"title\":\"报警信息\",\"content\":\"针盒二维码还在缓存库未出库\",\"buttons\":{\"dupQrcode\":\"确认\",\"dupQrcodecancel\":\"取消\"}}";
                    webSocketHandler.sendAlert(alertMessage);
                    System.out.println("[" + new Date() + "] 警报消息已发送");

                    return;
                }
                //判断是否重复处理二维码，入库中
                wmsCellInfoQuery.setCellStatus(BusinessConstants.CELL_STATUS_2);
                // 获取Service实例
                List<WmsCellInfo> list4 = wmsCellInfoService.selectWmsCellInfoList(wmsCellInfoQuery);
                if(null != list4 && list4.size() > 0){
                    logger.info("二维码针盒 [" + message + "] 正在入库中");
                   return;
                }
*/
    }
}
